/*
    YmsgIRC - Program enabling YMSG chat clients to use IRC
    Copyright (C) 2011 Crash Daemonicus ( crashenator -at- gmail.com )

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

/**
@file common.h
@brief Commonly used functions and debugging

Provides commonly-used includes; functions for manipulating strings, memory and logic, and functions for 
printing useful debugging textwith minimal effort.
@author crashenator (crashenator -at- gmail.com)
*/

#pragma once

#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_DEPRECATE
#pragma warning( disable : 4996 )
#endif

#include <cstdio>
#include <cstdlib>
#include <string.h>
#include <string>
#include <algorithm>
#include <vector>
using namespace std;

#ifdef _WIN32
	#define WIN32_LEAN_AND_MEAN
	/*#define NOSERVICE
	#define NOMCX
	#define NOIME*/
    #include <windows.h>
    #define DLLIMPORT __declspec(dllimport)
    #include "ChatRenderer.h"
    #pragma comment(lib, "ChatRenderer.lib")//ChatRenderer.lib by Wicked
#else
    #include <sys/unistd.h>
    //chatrenderer support??
#endif

/// @brief Specifies if debugging function-calls should be included in the build.
/// @details A value of 0 will cause debugging macros used as functions to be null.
#define COMMON_DBG 1

// comment the above if not needed;
// you will have to rebuild the project to correctly link after changing it.


#define NIMP(a,b) (a&(~b))///< nonimplication - A but not B
#define UNSET(a,b) NIMP(a,b)///< NIMP alias
#define UNSET_VAR(a,b) a&=~b
///< @brief Nonimplicative assignment - Unset flags in A as specified in B
///< @details safely unset flags contained in A with flags specified in B
///< where a-b  and  a XOR b are both unsafe  0011 NIMP 1010 = 0001


#define RWORD(w) MAKEWORD(HIBYTE(w),LOBYTE(w))///< Reverse the bytes in a WORD.
#define MAKEDWORD(p,q,r,s) MAKEWORD(p,q)|(MAKEWORD(r,s)<<16)
#define MEMZERO(p,l) memset(p, 0, l)///< null a length of memory
#define repstr(a,b) delstr(&a);a=newstr(b);///< free and set a C string pointer to a new heap-copy of a different C string 
#define streq(a,b) (strcmp(a,b)==0)///< boolean comparison for C strings
#define stoi(s) atoi((s).c_str())///< string object to integer

#define foreach_list(x,y,z) for(list<x>::iterator y=z.begin();y!=z.end();y++)//vector-type iterator-name vector
#define foreach_vector(x,y,z) for(vector<x>::iterator y=z.begin();y!=z.end();y++)//vector-type iterator-name vector
#define foreach_vector_const(x,y,z) for(vector<x>::const_iterator y=z.begin();y!=z.end();y++)//vector-type iterator-name vector
#define foreach_strchar(x,y) for(int x=0;x<strlen(y);x++)//iterator-name cstring
#define foreach_stringchar(x,y) for(string::size_type x=0;x<y.length();x++)//iterator-name string



#define QUOTE(x) #x
#define QUOTE2(x) QUOTE(x)

#ifdef COMMON_DBG
    /*debugging structure:
        int functionname(){
            dbg_head("functionname()");
            if(condition){
                ReturnX(2,"commentForThisReturn");// like return 2
            }
            ReturnD(1);//equivalent to  "return 1;" with debug info printed
        }
        void functionname2(){
            dbg_head("functionname2()");
            dbgline("miscDebugComment");
            if(condition){
            }
            dbg_foot();// or dbg_foot("debugComment");
        }
        // Head increases debug level (depth and text indention)
        // Foot and ReturnD/ReturnX decrease debug level
        // Line is indented to the debug level, but does not effect the level
    */
    void dbghead(const char* c=0,const char* file=0,int line=-1);
    void dbgfoot(const char* c=0,const char* file=0,int line=-1);
    void dbgtext(const char* c,bool indent=false,const char* file=0,int line=-1);
    void dbgtext(const string& s,bool indent=false,const char* file=0,int line=-1);
    #define dbg(v) dbgtext(v)
    #define dbg_do(a) a
    #define dbg_head(v) dbghead(v,__FILE__,__LINE__)
    #define dbg_foot(v) dbgfoot(v,__FILE__,__LINE__)
    #define dbgline(v) dbgtext(v,true,__FILE__,__LINE__)
    #define dbg_code(a) { dbg_head("DBG_CODE ");dbgline(#a);a;dbg_foot("DBG_CODE"); }

    
    #define ThrowD(e) dbg("Exception Thrown: " #e);throw e;
    #define CatchD(e) catch(e){ dbg("Exception Caught: " #e);
    #define ReturnD(r) { dbgfoot("Return: " #r,__FILE__,__LINE__); return r; }
    #define ReturnX(r,s) { dbgfoot(#s " - Return: " #r,__FILE__,__LINE__);return r; }
    
template <typename T>
void dbg_vec(const std::vector<T> &v1) {
	dbg_head(  (string(" vector<")+QUOTE(T)  +">").c_str() );
	foreach_vector_const(T,it,v1){
		(*it).debug();
	}
	dbg_foot(0);
}


#else
    #define dbg_code(a) 
    #define dbg_do(a) 
    #define dbg_head(...) 
    #define dbg_foot(...) 
    #define dbg(v) 
    #define dbgline(v) 
    
    #define ThrowD(e) throw e;
    #define CatchD(e) catch(e){
    #define ReturnD(r) return r;
    #define ReturnX(r,s) return r;




#endif
string itos(int i);///< creates a string object from an interger
int iLimit(int val, int min, int max);///< applies lower and upper limitations to an integer value
bool iCheckLimit(int val, int min, int max);///< checks if an integer value is within (or equal to) lower and upper limitations.

/**
@brief Split a string into a vector of tokens using a delimiter list.
@details This function produces a vector of substrings that were followed by a delimeter.
It should be noted that because of that process, this function ignores leading delimiters and any trailing substring.

This function was is used from: http://www.digitalpeer.com/id/simple (see Author below).  
It was used as an example to make StringExplode().

@param [in] str string to be tokenized
@param [out] tokens reference to a vector that tokens will be added to.
@param [in] delimeters a list of characters that separate tokens in the input (defaults to space)
@return none
@code
vector<string> tokens;
string str="|,|ab,c|de,zz";
string delims="|,";
StringTokenize(str,tokens,delims);
//tokens now contains: "ab","c","de"
@endcode
@see StringExplode()
@author J.D. Henderson (digitalpeer -at- digitalpeer.com)
@author Eric Hu?
*/
void StringTokenize(const string& str,
                      vector<string>& tokens,
                      const string& delimiters = " ");


/**
@brief Split a string into a vector of parts using a boundary string.
@details This function produces a vector of substrings that were followed by a boundary-string (delimiter).
It should be noted that because of that process, this function ignores a leading delimiter and any trailing substring.
This function works similarly (aside from the above) to PHP's explode() function.
This function is also different from StringTokenize as splits where a string occurs rather than single characters.

The implementation for this function was influenced by understanding StringTokenize() (different author)

@param [in] str string to be split
@param [out] parts reference to a vector that substrings will be added to.
@param [in] delimiter a boundary string that marks where the input should be split at.
@return none
@code
vector<string> tokens;
string str="|SPLIT|ab|c|SPLIT|de|SPLIT|zz";
string delims="|SPLIT|";
StringTokenize(str,tokens,delims);
//tokens now contains: "ab|c","de"
@endcode
@see StringTokenize()
@author crashenator (crashenator -at- gmail.com)
*/
void StringExplode(const string& str, vector<string>& parts, const string& delimiter = " ");


string stringtok(const string& str,const string& delimiters = " ");///< a wrapper for StringTokenize for string-objects that works similar to strtok

bool stringreplace(string& s, const string& sub, const string& sub2);


void MemReverse(void* p,int l);
//void MemZero(void* p,int l);

void puts(const string&);
void cputs(const string&);
void cputs(const char*);

const char* str_trimleft(const char* s,int n);



/**
@brief Create a heap copy of a string
@details This function is preferred for use ONLY when a function returns a temporary string (char*) that will change.
The created char-array size will be [length+1] and the last char will be set to NULL.
Note: if `c` is NULL and `safe` is True, the resulting empty string will obey the `alloc` parameter exclusively.
Note: if `c` is NULL and `safe` is False, this function will fail.
@param c temporary string-pointer
@param safe If the input pointer is NULL, this parameter ensures creation of a new (empty) string when true.
@param alloc specifies a static length for the string. If this parameter is 0 and the input pointer is not NULL, the length becomes strlen(c).
@return Success: a pointer to a copy of the original string on the heap. Failure: NULL


@see delstr(char** pc)
@see delstr(const char** pc)
*/
char* newstr(const char* c, bool safe=true,int alloc=0);


bool delstr(const char** pc);
/**<
@brief delete a heap string that has not been changed (assumes static length) and null the used pointer
@details Ease-of-use wrapper for delete[] and assignment in one.
@param pc pointer to a string-pointer (const char*).
@return returns `true` if the process succeeded.
@see newstr()
@see delstr(char** pc)
*/
bool delstr(char** pc);
/**<
@brief delete a heap string that has not been changed (assumes static length) and null the used pointer
@details Ease-of-use wrapper for delete[] and assignment in one.
2nd one because (char**)->(const char**) is invalid because of const 
qualifier-loss possibilities; even though the delstr() code doesn't violate 
constness AFAIK;   the goal is to release the char[] and null the char* in each.
@param pc pointer to a string-pointer (char*).
@return returns `true` if the process succeeded.
@see newstr()
@see delstr(const char** pc)
*/



template <typename T>
void operator+=(std::vector<T> &v1, const std::vector<T> &v2) { v1.insert(v1.end(), v2.begin(), v2.end()); }

template <typename T>
void operator+=(std::vector<T> &v1, const T &t1) { v1.push_back(t1);}

template <typename T>
void operator>>(const T &t1,std::vector<T> &v1) { v1.insert(v1.begin(),t1); }


template <typename T>
std::vector<T> operator+(const std::vector<T> &v1, const std::vector<T> &v2) {
	std::vector<T> vec=v1;
	vec+=v2;
	return vec;
}

template <typename T>
std::vector<T> operator+(const std::vector<T> &v1, const T &t1)
{
	std::vector<T> vec=v1;
	vec+=t1;
	return vec;
}

template <typename T>
std::vector<T> operator+(const T &t1,const std::vector<T> &v1) { 
	std::vector<T> vec=v1;
	t1>>vec;
	return vec;
}
